bitkeeper revision 1.825.3.10 (4065558aPBWky8sW_ub8imsOf_yTwg)
authorkaf24@scramble.cl.cam.ac.uk <kaf24@scramble.cl.cam.ac.uk>
Sat, 27 Mar 2004 10:20:58 +0000 (10:20 +0000)
committerkaf24@scramble.cl.cam.ac.uk <kaf24@scramble.cl.cam.ac.uk>
Sat, 27 Mar 2004 10:20:58 +0000 (10:20 +0000)
Many files:
  Cleaned up user-space event-channel handling (now better reflects the underlying abstraction). Also simplified handling of exceptional notifications (now a special case of a normal notification).

tools/xend/lib/main.py
tools/xend/lib/manager.py
tools/xend/lib/utils.c
xen/common/event_channel.c
xen/include/hypervisor-ifs/hypervisor-if.h
xen/include/xen/event.h
xenolinux-2.4.25-sparse/arch/xen/drivers/console/console.c
xenolinux-2.4.25-sparse/arch/xen/drivers/evtchn/evtchn.c
xenolinux-2.4.25-sparse/arch/xen/kernel/evtchn.c
xenolinux-2.4.25-sparse/include/asm-xen/evtchn.h

index 6cbfa5ad356fb45663a0fe292a7408a69585fc72..4b243b330726000de3009786b8934481756daba5 100755 (executable)
@@ -41,8 +41,7 @@ def daemon_loop():
 
     # Interface via which we receive event notifications from other guest
     # OSes. This interface also allows us to clear/acknowledge outstanding
-    # notifications --- successive notifications for the same channel are
-    # dropped until the first notification is cleared.
+    # notifications.
     notifier = xend.utils.notifier()
 
     ##
@@ -169,56 +168,48 @@ def daemon_loop():
                 break
             (idx, type) = notification
 
+            if not control_list.has_key(idx):
+                continue
+
+            (port, rbuf, wbuf, con_if) = control_list[idx]
+            work_done = False
+
             # If we pick up a disconnect notification then we do any necessary
-            # cleanup, even if the event channel doesn't belong to us.
-            # This is intended to prevent the event-channel port space from
-            # getting clogged with stale connections.
-            if type == notifier.DISCONNECT:
+            # cleanup.
+            if type == notifier.EXCEPTION:
                 ret = xc.evtchn_status(idx)
-                if ret['status'] == 'interdomain':
-                    notifier.clear(idx, notifier.NORMAL)
-                    notifier.clear(idx, notifier.DISCONNECT)
-                    if control_list.has_key(idx):
-                        (port, rbuf, wbuf, con_if) =  control_list[idx]
-                        con_if.close()
-                        del control_list[idx], port, rbuf, wbuf, con_if
-                elif ret['status'] == 'unbound':
-                    # There's noone to do the closure for us...
-                    xc.evtchn_close(idx)
-
-            # A standard notification: probably means there are messages to
-            # read or that there is space to write messages.
-            elif type == notifier.NORMAL and control_list.has_key(idx):
-                (port, rbuf, wbuf, con_if) = control_list[idx]
-                work_done = False
-
-                # We clear the notification before doing any work, to avoid
-                # races.
-                notifier.clear(idx, notifier.NORMAL)
-
-                # Read incoming requests. Currently assume that request
-                # message always containb console data.
-                while port.request_to_read():
-                    msg = port.read_request()
-                    rbuf.write(msg.get_payload())
-                    port.write_response(msg)
-                    work_done = True
-
-                # Incoming responses are currently thrown on the floor.
-                while port.response_to_read():
-                    msg = port.read_response()
-                    work_done = True
-
-                # Send as much pending console data as there is room for.
-                while not wbuf.empty() and port.space_to_write_request():
-                    msg = xend.utils.message(0, 0, 0)
-                    msg.append_payload(wbuf.read(msg.MAX_PAYLOAD))
-                    port.write_request(msg)
-                    work_done = True
-
-                # Finally, notify the remote end of any work that we did.
-                if work_done:
-                    port.notify()
+                if ret['status'] == 'unbound':
+                    notifier.unbind(idx)
+                    con_if.close()
+                    del control_list[idx], port, rbuf, wbuf, con_if
+                    continue
+
+            # Read incoming requests. Currently assume that request
+            # message always containb console data.
+            while port.request_to_read():
+                msg = port.read_request()
+                rbuf.write(msg.get_payload())
+                port.write_response(msg)
+                work_done = True
+
+            # Incoming responses are currently thrown on the floor.
+            while port.response_to_read():
+                msg = port.read_response()
+                work_done = True
+
+            # Send as much pending console data as there is room for.
+            while not wbuf.empty() and port.space_to_write_request():
+                msg = xend.utils.message(0, 0, 0)
+                msg.append_payload(wbuf.read(msg.MAX_PAYLOAD))
+                port.write_request(msg)
+                work_done = True
+
+            # Finally, notify the remote end of any work that we did.
+            if work_done:
+                port.notify()
+
+            # Unmask notifications for this port.
+            notifier.unmask(idx)
 
 
 
index 092caa02fc49bcb61350fd41b40e5f16b9d97c82..8e336763f107fd63b4801be48dd9ee48f87c797f 100644 (file)
@@ -14,10 +14,9 @@ import xend.console, xend.main, xend.utils
 ##  automatically allocated.
 ##
 def new_control_interface(dom, console_port=-1):
-    # Allocate an event channel. Clear pending notifications.
+    # Allocate an event channel and binbd to it.
     port = xend.utils.port(dom)
-    xend.main.notifier.clear(port.local_port, xend.main.notifier.NORMAL)
-    xend.main.notifier.clear(port.local_port, xend.main.notifier.DISCONNECT)
+    xend.main.notifier.bind(port.local_port)
     
     # If necessary, compute a suitable TCP port for console I/O.
     if console_port < 0:
index e57b7ed9d32f8cd6c473e5ec82dc7826102252f1..6a531da0ccd6dad3885d1ece87c8b27c6823d6a5 100644 (file)
 #define EVTCHN_DEV_MAJOR 10
 #define EVTCHN_DEV_MINOR 200
 #define PORT_NORMAL     0x0000   /* A standard event notification.      */ 
-#define PORT_DISCONNECT 0x8000   /* A port-disconnect notification.     */
+#define PORT_EXCEPTION  0x8000   /* An exceptional notification.        */
 #define PORTIDX_MASK    0x7fff   /* Strip subtype to obtain port index. */
-#define EVTCHN_RESET _IO('E', 1) /* Clear notification buffer. Clear errors. */
+/* /dev/xen/evtchn ioctls: */
+/* EVTCHN_RESET: Clear and reinit the event buffer. Clear error condition. */
+#define EVTCHN_RESET  _IO('E', 1)
+/* EVTCHN_BIND: Bind to teh specified event-channel port. */
+#define EVTCHN_BIND   _IO('E', 2)
+/* EVTCHN_UNBIND: Unbind from the specified event-channel port. */
+#define EVTCHN_UNBIND _IO('E', 3)
 
 /* Size of a machine page frame. */
 #define PAGE_SIZE 4096
@@ -76,23 +82,53 @@ static PyObject *xu_notifier_read(PyObject *self, PyObject *args)
     return Py_None;
 }
 
-static PyObject *xu_notifier_clear(PyObject *self, PyObject *args)
+static PyObject *xu_notifier_unmask(PyObject *self, PyObject *args)
 {
     xu_notifier_object *xun = (xu_notifier_object *)self;
     u16 v;
-    int idx, type;
+    int idx;
 
-    if ( !PyArg_ParseTuple(args, "ii", &idx, &type) )
+    if ( !PyArg_ParseTuple(args, "i", &idx) )
         return NULL;
-    
-    v = (u16)idx | (u16)type;
 
+    v = (u16)idx;
+    
     (void)write(xun->evtchn_fd, &v, sizeof(v));
 
     Py_INCREF(Py_None);
     return Py_None;
 }
 
+static PyObject *xu_notifier_bind(PyObject *self, PyObject *args)
+{
+    xu_notifier_object *xun = (xu_notifier_object *)self;
+    int idx;
+
+    if ( !PyArg_ParseTuple(args, "i", &idx) )
+        return NULL;
+
+    if ( ioctl(xun->evtchn_fd, EVTCHN_BIND, idx) != 0 )
+        return PyErr_SetFromErrno(PyExc_IOError);
+
+    Py_INCREF(Py_None);
+    return Py_None;
+}
+
+static PyObject *xu_notifier_unbind(PyObject *self, PyObject *args)
+{
+    xu_notifier_object *xun = (xu_notifier_object *)self;
+    int idx;
+
+    if ( !PyArg_ParseTuple(args, "i", &idx) )
+        return NULL;
+
+    if ( ioctl(xun->evtchn_fd, EVTCHN_UNBIND, idx) != 0 )
+        return PyErr_SetFromErrno(PyExc_IOError);
+
+    Py_INCREF(Py_None);
+    return Py_None;
+}
+
 static PyObject *xu_notifier_fileno(PyObject *self, PyObject *args)
 {
     xu_notifier_object *xun = (xu_notifier_object *)self;
@@ -105,10 +141,20 @@ static PyMethodDef xu_notifier_methods[] = {
       METH_VARARGS,
       "Read a (@port, @type) pair.\n" },
 
-    { "clear", 
-      (PyCFunction)xu_notifier_clear,
+    { "unmask", 
+      (PyCFunction)xu_notifier_unmask,
+      METH_VARARGS,
+      "Unmask notifications for a @port.\n" },
+
+    { "bind", 
+      (PyCFunction)xu_notifier_bind,
+      METH_VARARGS,
+      "Get notifications for a @port.\n" },
+
+    { "unbind", 
+      (PyCFunction)xu_notifier_unbind,
       METH_VARARGS,
-      "Clear a (@port, @type) pair.\n" },
+      "No longer get notifications for a @port.\n" },
 
     { "fileno", 
       (PyCFunction)xu_notifier_fileno,
@@ -147,8 +193,8 @@ static PyObject *xu_notifier_new(PyObject *self, PyObject *args)
 
 static PyObject *xu_notifier_getattr(PyObject *obj, char *name)
 {
-    if ( strcmp(name, "DISCONNECT") == 0 )
-        return PyInt_FromLong(PORT_DISCONNECT);
+    if ( strcmp(name, "EXCEPTION") == 0 )
+        return PyInt_FromLong(PORT_EXCEPTION);
     if ( strcmp(name, "NORMAL") == 0 )
         return PyInt_FromLong(PORT_NORMAL);
     return Py_FindMethod(xu_notifier_methods, obj, name);
index d68e28b5537f59885fdbac7ca0679e177c5878e6..af20f8b53368155f6cb4d9b4c895bbd507ed0dc9 100644 (file)
@@ -154,11 +154,11 @@ static long evtchn_bind_virq(evtchn_bind_virq_t *bind)
 
     /*
      * Port 0 is the fallback port for VIRQs that haven't been explicitly
-     * bound yet. The exception is the 'error VIRQ', which is permanently 
+     * bound yet. The exception is the 'misdirect VIRQ', which is permanently 
      * bound to port 0.
      */
     if ( ((port = p->virq_to_evtchn[virq]) != 0) ||
-         (virq == VIRQ_ERROR) ||
+         (virq == VIRQ_MISDIRECT) ||
          ((port = get_free_port(p)) < 0) )
         goto out;
 
@@ -226,7 +226,7 @@ static long __evtchn_close(struct task_struct *p1, int port1)
 
     chn1 = p1->event_channel;
 
-    /* NB. Port 0 is special (VIRQ_ERROR). Never let it be closed. */
+    /* NB. Port 0 is special (VIRQ_MISDIRECT). Never let it be closed. */
     if ( (port1 <= 0) || (port1 >= p1->max_event_channel) )
     {
         rc = -EINVAL;
@@ -483,7 +483,7 @@ int init_event_channels(struct task_struct *p)
     p->max_event_channel = INIT_EVENT_CHANNELS;
     memset(p->event_channel, 0, INIT_EVENT_CHANNELS * sizeof(event_channel_t));
     p->event_channel[0].state  = ECS_VIRQ;
-    p->event_channel[0].u.virq = VIRQ_ERROR;
+    p->event_channel[0].u.virq = VIRQ_MISDIRECT;
     return 0;
 }
 
index 335baee58183d8a2053f94184c910c00b6c3a5a3..2b27b4b8248e755ee579a1a063a3336fdc4fd4d9 100644 (file)
  * Virtual interrupts that a guest OS may receive from the hypervisor.
  */
 
-#define VIRQ_BLKDEV    0  /* A block device response has been queued. */
-#define VIRQ_TIMER     1  /* A timeout has been updated. */
-#define VIRQ_DIE       2  /* OS is about to be killed. Clean up please! */
-#define VIRQ_DEBUG     3  /* Request guest to dump debug info (gross!) */
-#define VIRQ_NET       4  /* There are packets for transmission. */
-#define VIRQ_PS2       5  /* PS/2 keyboard or mouse event(s) */
-#define VIRQ_STOP      6  /* Prepare for stopping and possible pickling */
-#define VIRQ_EVTCHN    7  /* Event pending on an event channel */
-#define VIRQ_VBD_UPD   8  /* Event to signal VBDs should be reprobed */
-#define VIRQ_CONSOLE   9  /* This is only for domain-0 initial console. */
-#define VIRQ_PHYSIRQ  10  /* Event to signal pending physical IRQs. */
-#define VIRQ_ERROR    11  /* Catch-all virtual interrupt. */
-#define NR_VIRQS      12
+#define VIRQ_BLKDEV     0  /* A block device response has been queued. */
+#define VIRQ_TIMER      1  /* A timeout has been updated. */
+#define VIRQ_DIE        2  /* OS is about to be killed. Clean up please! */
+#define VIRQ_DEBUG      3  /* Request guest to dump debug info (gross!) */
+#define VIRQ_NET        4  /* There are packets for transmission. */
+#define VIRQ_PS2        5  /* PS/2 keyboard or mouse event(s) */
+#define VIRQ_STOP       6  /* Prepare for stopping and possible pickling */
+#define VIRQ_EVTCHN     7  /* Event pending on an event channel */
+#define VIRQ_VBD_UPD    8  /* Event to signal VBDs should be reprobed */
+#define VIRQ_CONSOLE    9  /* This is only for domain-0 initial console. */
+#define VIRQ_PHYSIRQ   10  /* Event to signal pending physical IRQs. */
+#define VIRQ_MISDIRECT 11  /* Catch-all virtual interrupt. */
+#define NR_VIRQS       12
 
 /*
  * MMU_XXX: specified in least 2 bits of 'ptr' field. These bits are masked
@@ -187,23 +187,22 @@ typedef struct shared_info_st
      *  2. EXCEPTION -- notifies the domain that there has been some
      *     exceptional event associated with this channel (e.g. remote
      *     disconnect, physical IRQ error). This bit is cleared by the guest.
+     *     A 0->1 transition of this bit will cause the PENDING bit to be set.
      *  3. MASK -- if this bit is clear then a 0->1 transition of PENDING
-     *     or EXCEPTION will cause an asynchronous upcall to be scheduled.
-     *     This bit is only updated by the guest. It is read-only within Xen.
-     *     If a channel becomes pending or an exceptional event occurs while
-     *     the channel is masked then the 'edge' is lost (i.e., when the
-     *     channel is unmasked, the guest must manually handle pending
-     *     notifications as no upcall will be scheduled by Xen).
+     *     will cause an asynchronous upcall to be scheduled. This bit is only
+     *     updated by the guest. It is read-only within Xen. If a channel
+     *     becomes pending while the channel is masked then the 'edge' is lost
+     *     (i.e., when the channel is unmasked, the guest must manually handle
+     *     pending notifications as no upcall will be scheduled by Xen).
      * 
-     * To expedite scanning of pending notifications and exceptions, any 
-     * 0->1 transition on an unmasked channel causes a corresponding bit in
-     * 32-bit selector to be set. Each bit in the selector covers a 32-bit
-     * word in the PENDING or EXCEPTION bitfield array.
+     * To expedite scanning of pending notifications, any 0->1 pending
+     * transition on an unmasked channel causes a corresponding bit in a
+     * 32-bit selector to be set. Each bit in the selector covers a 32-bit
+     * word in the PENDING bitfield array.
      */
     u32 evtchn_pending[32];
     u32 evtchn_pending_sel;
     u32 evtchn_exception[32];
-    u32 evtchn_exception_sel;
     u32 evtchn_mask[32];
 
     /*
index e471e56afd3e3c99d011efcdced097d44498b955..3dd4cf383edbc897ed6d2e3068b95bf8cf2fafee 100644 (file)
@@ -71,11 +71,8 @@ static inline void evtchn_set_pending(struct task_struct *p, int port)
 
 static inline void evtchn_set_exception(struct task_struct *p, int port)
 {
-    shared_info_t *s = p->shared_info;
-    if ( !test_and_set_bit(port,    &s->evtchn_exception[0]) &&
-         !test_bit        (port,    &s->evtchn_mask[0])      &&
-         !test_and_set_bit(port>>5, &s->evtchn_exception_sel) )
-        guest_notify(p);
+    if ( !test_and_set_bit(port, &p->shared_info->evtchn_exception[0]) )
+        evtchn_set_pending(p, port);
 }
 
 /*
index 8b76e8ab4e2625bfe0faf03cbd1b02fa41d54c08..222097f20d66eefa4271f4c84775169ccbb71b84 100644 (file)
@@ -143,8 +143,6 @@ void xen_console_init(void)
     }
 
     register_console(&kcons_info);
-
-    evtchn_clear_error_virq();
 }
 
 
index faa1bb0b6173b1125ea12cfa6a2500f18696bfc7..985d72821d251860edbc0ac0f4b291ec69539f7d 100644 (file)
@@ -40,35 +40,25 @@ static unsigned int ring_cons, ring_prod, ring_overflow;
 static DECLARE_WAIT_QUEUE_HEAD(evtchn_wait);
 static struct fasync_struct *evtchn_async_queue;
 
-/*
- * Pending normal notifications and pending exceptional notifications.
- * 'Pending' means that we received an upcall but this is not yet ack'ed
- * from userspace by writing to /dev/xen/evtchn.
- */
-static u32 pend_nrm[32], pend_exc[32];
+/* Which ports is user-space bound to? */
+static u32 bound_ports[32];
 
 static spinlock_t lock;
 
-void evtchn_device_upcall(int port, int exception)
+void evtchn_device_upcall(int port)
 {
     u16 port_subtype;
+    shared_info_t *s = HYPERVISOR_shared_info;
 
     spin_lock(&lock);
 
     mask_evtchn(port);
+    clear_evtchn(port);
 
-    if ( likely(!exception) )
-    {
-        clear_evtchn(port);
-        set_bit(port, &pend_nrm[0]);
+    if ( likely(!synch_test_and_clear_bit(port, &s->evtchn_exception[0])) )
         port_subtype = PORT_NORMAL;
-    }
     else
-    {
-        clear_evtchn_exception(port);
-        set_bit(port, &pend_exc[0]);
         port_subtype = PORT_EXCEPTION;
-    }
 
     if ( ring != NULL )
     {
@@ -92,28 +82,8 @@ void evtchn_device_upcall(int port, int exception)
 
 static void __evtchn_reset_buffer_ring(void)
 {
-    u32          m;
-    unsigned int i, j;
-
-    /* Initialise the ring with currently outstanding notifications. */
+    /* Initialise the ring to empty. Clear errors. */
     ring_cons = ring_prod = ring_overflow = 0;
-
-    for ( i = 0; i < 32; i++ )
-    {
-        m = pend_exc[i];
-        while ( (j = ffs(m)) != 0 )
-        {
-            m &= ~(1 << --j);
-            ring[ring_prod++] = (u16)(((i * 32) + j) | PORT_EXCEPTION);
-        }
-
-        m = pend_nrm[i];
-        while ( (j = ffs(m)) != 0 )
-        {
-            m &= ~(1 << --j);
-            ring[ring_prod++] = (u16)(((i * 32) + j) | PORT_NORMAL);
-        }
-    }
 }
 
 static ssize_t evtchn_read(struct file *file, char *buf,
@@ -232,11 +202,8 @@ static ssize_t evtchn_write(struct file *file, const char *buf,
 
     spin_lock_irq(&lock);
     for ( i = 0; i < (count/2); i++ )
-    {
-        clear_bit(kbuf[i]&PORTIDX_MASK, 
-                  (kbuf[i]&PORT_EXCEPTION) ? &pend_exc[0] : &pend_nrm[0]);
-        unmask_evtchn(kbuf[i]&PORTIDX_MASK);
-    }
+        if ( test_bit(kbuf[i], &bound_ports[0]) )
+            unmask_evtchn(kbuf[i]);
     spin_unlock_irq(&lock);
 
     rc = count;
@@ -249,14 +216,35 @@ static ssize_t evtchn_write(struct file *file, const char *buf,
 static int evtchn_ioctl(struct inode *inode, struct file *file,
                         unsigned int cmd, unsigned long arg)
 {
-    if ( cmd != EVTCHN_RESET )
-        return -EINVAL;
-
+    int rc = 0;
+    
     spin_lock_irq(&lock);
-    __evtchn_reset_buffer_ring();
+    
+    switch ( cmd )
+    {
+    case EVTCHN_RESET:
+        __evtchn_reset_buffer_ring();
+        break;
+    case EVTCHN_BIND:
+        if ( !test_and_set_bit(arg, &bound_ports[0]) )
+            unmask_evtchn(arg);
+        else
+            rc = -EINVAL;
+        break;
+    case EVTCHN_UNBIND:
+        if ( test_and_clear_bit(arg, &bound_ports[0]) )
+            mask_evtchn(arg);
+        else
+            rc = -EINVAL;
+        break;
+    default:
+        rc = -ENOSYS;
+        break;
+    }
+
     spin_unlock_irq(&lock);   
 
-    return 0;
+    return rc;
 }
 
 static unsigned int evtchn_poll(struct file *file, poll_table *wait)
@@ -298,12 +286,17 @@ static int evtchn_open(struct inode *inode, struct file *filp)
 
 static int evtchn_release(struct inode *inode, struct file *filp)
 {
+    int i;
+
     spin_lock_irq(&lock);
     if ( ring != NULL )
     {
         free_page((unsigned long)ring);
         ring = NULL;
     }
+    for ( i = 0; i < NR_EVENT_CHANNELS; i++ )
+        if ( test_and_clear_bit(i, &bound_ports[0]) )
+            mask_evtchn(i);
     spin_unlock_irq(&lock);
 
     evtchn_dev_inuse = 0;
index 4eb83c4b4cf5493c7eeee5ee6fc72435677d8b9c..fc3efb810ea74160f6b6eef98e0703eff0438758 100644 (file)
@@ -38,76 +38,37 @@ static int irq_bindcount[NR_IRQS];
 /* Upcall to generic IRQ layer. */
 extern asmlinkage unsigned int do_IRQ(int irq, struct pt_regs *regs);
 
-static void evtchn_handle_normal(shared_info_t *s, struct pt_regs *regs)
-{
-    unsigned long l1, l2;
-    unsigned int  l1i, l2i, port;
-    int           irq;
-
-    l1 = xchg(&s->evtchn_pending_sel, 0);
-    while ( (l1i = ffs(l1)) != 0 )
-    {
-        l1i--;
-        l1 &= ~(1 << l1i);
-        
-        l2 = s->evtchn_pending[l1i] & ~s->evtchn_mask[l1i];
-        while ( (l2i = ffs(l2)) != 0 )
-        {
-            l2i--;
-            l2 &= ~(1 << l2i);
-            
-            port = (l1i << 5) + l2i;
-            if ( (irq = evtchn_to_irq[port]) != -1 )
-                do_IRQ(irq, regs);
-            else
-                evtchn_device_upcall(port, 0);
-        }
-    }
-}
-
-static void evtchn_handle_exceptions(shared_info_t *s, struct pt_regs *regs)
-{
-    unsigned long l1, l2;
-    unsigned int  l1i, l2i, port;
-    int           irq;
-
-    l1 = xchg(&s->evtchn_exception_sel, 0);
-    while ( (l1i = ffs(l1)) != 0 )
-    {
-        l1i--;
-        l1 &= ~(1 << l1i);
-        
-        l2 = s->evtchn_exception[l1i] & ~s->evtchn_mask[l1i];
-        while ( (l2i = ffs(l2)) != 0 )
-        {
-            l2i--;
-            l2 &= ~(1 << l2i);
-            
-            port = (l1i << 5) + l2i;
-            if ( (irq = evtchn_to_irq[port]) != -1 )
-            {
-                printk(KERN_ALERT "Error on IRQ line %d!\n", irq);
-                synch_clear_bit(port, &s->evtchn_exception[0]);
-            }
-            else
-                evtchn_device_upcall(port, 1);
-        }
-    }
-}
-
 void evtchn_do_upcall(struct pt_regs *regs)
 {
-    unsigned long flags;
+    unsigned long  l1, l2;
+    unsigned int   l1i, l2i, port;
+    int            irq;
+    unsigned long  flags;
     shared_info_t *s = HYPERVISOR_shared_info;
 
     local_irq_save(flags);
     
     while ( synch_test_and_clear_bit(0, &s->evtchn_upcall_pending) )
     {
-        if ( s->evtchn_pending_sel != 0 )
-            evtchn_handle_normal(s, regs);
-        if ( s->evtchn_exception_sel != 0 )
-            evtchn_handle_exceptions(s, regs);
+        l1 = xchg(&s->evtchn_pending_sel, 0);
+        while ( (l1i = ffs(l1)) != 0 )
+        {
+            l1i--;
+            l1 &= ~(1 << l1i);
+        
+            l2 = s->evtchn_pending[l1i] & ~s->evtchn_mask[l1i];
+            while ( (l2i = ffs(l2)) != 0 )
+            {
+                l2i--;
+                l2 &= ~(1 << l2i);
+            
+                port = (l1i << 5) + l2i;
+                if ( (irq = evtchn_to_irq[port]) != -1 )
+                    do_IRQ(irq, regs);
+                else
+                    evtchn_device_upcall(port);
+            }
+        }
     }
 
     local_irq_restore(flags);
@@ -346,16 +307,16 @@ static struct hw_interrupt_type pirq_type = {
     NULL
 };
 
-static void error_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static void misdirect_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 {
-    printk(KERN_ALERT "unexpected VIRQ_ERROR trap to vector %d\n", irq);
+    /* nothing */
 }
 
-static struct irqaction error_action = {
-    error_interrupt, 
+static struct irqaction misdirect_action = {
+    misdirect_interrupt, 
     SA_INTERRUPT, 
     0, 
-    "error", 
+    "misdirect", 
     NULL, 
     NULL
 };
@@ -372,7 +333,10 @@ void __init init_IRQ(void)
 
     /* No event-channel -> IRQ mappings. */
     for ( i = 0; i < NR_EVENT_CHANNELS; i++ )
+    {
         evtchn_to_irq[i] = -1;
+        mask_evtchn(i); /* No event channels are 'live' right now. */
+    }
 
     /* No IRQ -> event-channel mappings. */
     for ( i = 0; i < NR_IRQS; i++ )
@@ -400,5 +364,5 @@ void __init init_IRQ(void)
         irq_desc[pirq_to_irq(i)].handler = &pirq_type;
     }
 
-    (void)setup_irq(bind_virq_to_irq(VIRQ_ERROR), &error_action);
+    (void)setup_irq(bind_virq_to_irq(VIRQ_MISDIRECT), &misdirect_action);
 }
index fd52b97009f57d72b08b33d8b88e0b63c8162185..8dbb460cdacfc02d24daacb2964ef8228fbbad8c 100644 (file)
@@ -23,7 +23,7 @@
 void evtchn_do_upcall(struct pt_regs *regs);
 
 /* Entry point for notifications into the userland character device. */
-void evtchn_device_upcall(int port, int exception);
+void evtchn_device_upcall(int port);
 
 static inline void mask_evtchn(int port)
 {
@@ -34,7 +34,6 @@ static inline void mask_evtchn(int port)
 static inline void unmask_evtchn(int port)
 {
     shared_info_t *s = HYPERVISOR_shared_info;
-    int need_upcall = 0;
 
     synch_clear_bit(port, &s->evtchn_mask[0]);
 
@@ -42,19 +41,8 @@ static inline void unmask_evtchn(int port)
      * The following is basically the equivalent of 'hw_resend_irq'. Just like
      * a real IO-APIC we 'lose the interrupt edge' if the channel is masked.
      */
-
-    /* Asserted a standard notification? */
     if (  synch_test_bit        (port,    &s->evtchn_pending[0]) && 
-         !synch_test_and_set_bit(port>>5, &s->evtchn_pending_sel) )
-        need_upcall = 1;
-
-    /* Asserted an exceptional notification? */
-    if (  synch_test_bit        (port,    &s->evtchn_exception[0]) && 
-         !synch_test_and_set_bit(port>>5, &s->evtchn_exception_sel) )
-        need_upcall = 1;
-
-    /* If asserted either type of notification, check the master flags. */
-    if ( need_upcall &&
+         !synch_test_and_set_bit(port>>5, &s->evtchn_pending_sel) &&
          !synch_test_and_set_bit(0,       &s->evtchn_upcall_pending) &&
          !synch_test_bit        (0,       &s->evtchn_upcall_mask) )
         evtchn_do_upcall(NULL);
@@ -72,16 +60,6 @@ static inline void clear_evtchn_exception(int port)
     synch_clear_bit(port, &s->evtchn_exception[0]);
 }
 
-static inline void evtchn_clear_error_virq(void)
-{
-    /*
-     * XXX This prevents a bogus 'VIRQ_ERROR' when interrupts are enabled
-     * for the first time. This works because by this point all important
-     * VIRQs (eg. timer) have been properly bound.
-     */
-    synch_clear_bit(0, &HYPERVISOR_shared_info->evtchn_pending[0]);
-}
-
 /*
  * CHARACTER-DEVICE DEFINITIONS
  */
@@ -95,6 +73,10 @@ static inline void evtchn_clear_error_virq(void)
 
 /* /dev/xen/evtchn ioctls: */
 /* EVTCHN_RESET: Clear and reinit the event buffer. Clear error condition. */
-#define EVTCHN_RESET _IO('E', 1)
+#define EVTCHN_RESET  _IO('E', 1)
+/* EVTCHN_BIND: Bind to teh specified event-channel port. */
+#define EVTCHN_BIND   _IO('E', 2)
+/* EVTCHN_UNBIND: Unbind from the specified event-channel port. */
+#define EVTCHN_UNBIND _IO('E', 3)
 
 #endif /* __ASM_EVTCHN_H__ */